﻿using System.Security.Cryptography;
using System.Text;

namespace Aurora.Security.RSA.Facility
{
    internal abstract class RSAFacilityBase
    {
        protected System.Security.Cryptography.RSA _privateRsa;
        protected System.Security.Cryptography.RSA _publicRsa;

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public async Task<string> EncryptAsync(string data, RSAEncryptionPadding padding)
        {
            return await Task.Run(() =>
            {
                if (_publicRsa == null)
                {
                    throw new ArgumentException("公钥不能为空");
                }
                else
                {
                    var publicKey = _publicRsa.ExportParameters(false);
                    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048))
                    {
                        rsa.ImportParameters(publicKey);
                        var bufferSize = 117;
                        byte[] buffer = new byte[bufferSize];//待加密块
                        using (MemoryStream msInput = new MemoryStream(Encoding.UTF8.GetBytes(data)))
                        {
                            using (MemoryStream msOutput = new MemoryStream())
                            {
                                int readLen;
                                while ((readLen = msInput.Read(buffer, 0, bufferSize)) > 0)
                                {
                                    byte[] dataToEnc = new byte[readLen];
                                    Array.Copy(buffer, 0, dataToEnc, 0, readLen);
                                    byte[] encData = rsa.Encrypt(dataToEnc, padding);
                                    msOutput.Write(encData, 0, encData.Length);
                                }
                                rsa.Clear();
                                return Convert.ToBase64String(msOutput.ToArray());
                            }
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="data"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public async Task<string> DecryptAsync(string data, RSAEncryptionPadding padding)
        {
            return await Task.Run(() =>
            {
                if (_privateRsa == null)
                {
                    throw new ArgumentException("私钥不能为空");
                }
                var privateKey = _privateRsa.ExportParameters(true);
                using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048))
                {
                    rsa.ImportParameters(privateKey);
                    int bufferSize = rsa.KeySize / 8;
                    var buffer = new byte[bufferSize];
                    using (MemoryStream inputStream = new MemoryStream(Convert.FromBase64String(data)))
                    {
                        using (MemoryStream outputStream = new MemoryStream())
                        {
                            int readSize;
                            while ((readSize = inputStream.Read(buffer, 0, bufferSize)) > 0)
                            {
                                var temp = new byte[readSize];
                                Array.Copy(buffer, 0, temp, 0, readSize);
                                var rawBytes = rsa.Decrypt(temp, padding);
                                outputStream.Write(rawBytes, 0, rawBytes.Length);
                            }
                            rsa.Clear();
                            return Encoding.UTF8.GetString(outputStream.ToArray());
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="data"></param>
        /// <param name="hash"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public async Task<string> SignDataAsync(string data, HashAlgorithmName hash, RSASignaturePadding padding)
        {
            return await Task.Run(() =>
            {
                if (_privateRsa == null)
                {
                    throw new ArgumentException("私钥不能为空");
                }
                var res = Convert.ToBase64String(_privateRsa.SignData(Encoding.UTF8.GetBytes(data), hash, padding));
                return res;
            });
        }

        /// <summary>
        /// 验签
        /// </summary>
        /// <param name="data">需要验签的数据</param>
        /// <param name="sign">已经签名的数据</param>
        /// <param name="hash"></param>
        /// <param name="padding"></param>
        /// <returns></returns>
        public async Task<bool> VerifyDataAsync(string data, string sign, HashAlgorithmName hash, RSASignaturePadding padding)
        {
            return await Task.Run(() =>
            {
                if (_publicRsa == null)
                {
                    throw new ArgumentException("公钥不能为空");
                }
                var res = _publicRsa.VerifyData(Encoding.UTF8.GetBytes(data), Convert.FromBase64String(sign), hash, padding);
                return res;
            });
        }

    }
}